package icu.zhhll.datasource.dynamic;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.FactoryBean;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 数据源配置示例
 * <bean id="dynamicProperties" class="icu.zhhll.datasource.dynamic.DynamicProperties">
 * <property name="dataSources">
 * <list>
 * <bean id="real1" class="icu.zhhll.datasource.dynamic.DynamicProperties.RealDataSource">
 * <property name="driverClassName" value="com.mysql.jdbc.Driver" />
 * <property name="url" value="jdbc:mysql://localhost:3306/spring?useUnicode=true&amp;characterEncoding=utf-8" />
 * <property name="username" value="root" />
 * <property name="password" value="123456" />
 * <property name="name" value="data01" />
 * <property name="type" value="com.alibaba.druid.pool.DruidDataSource"/>
 * </bean>
 * <bean id="real2" class="icu.zhhll.datasource.dynamic.DynamicProperties.RealDataSource">
 * <property name="driverClassName" value="com.mysql.jdbc.Driver" />
 * <property name="url" value="jdbc:mysql://localhost:3306/company?useUnicode=true&amp;characterEncoding=utf-8" />
 * <property name="username" value="root" />
 * <property name="password" value="123456" />
 * <property name="name" value="data02" />
 * <property name="type" value="com.alibaba.druid.pool.DruidDataSource"/>
 * </bean>
 * </list>
 * </property>
 * <property name="defaultDS" value="data01"/>
 * </bean>
 *
 * <bean id="dataSource" class="icu.zhhll.datasource.dynamic.DataSourceRegister">
 * <property name="dynamicProperties" ref="dynamicProperties"/>
 * </bean>
 * </p>
 * 数据源注册器
 *
 * @author zh
 * @date 2023/10/7 17:01
 */
public class DataSourceRegister implements FactoryBean<DataSource> {


    private DynamicProperties dynamicProperties;

    public DynamicProperties getDynamicProperties() {
        return dynamicProperties;
    }

    public void setDynamicProperties(DynamicProperties dynamicProperties) {
        this.dynamicProperties = dynamicProperties;
    }

    @Override
    public DataSource getObject() {
        if (StringUtils.isBlank(dynamicProperties.getDefaultDS())) {
            throw new RuntimeException("没有设置默认数据源");
        }
        Map<Object, Object> dataSourceMap = initAllRealDataSource();
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultDs(dynamicProperties.getDefaultDS());
        dynamicDataSource.setDefaultTargetDataSource(dataSourceMap.get(dynamicProperties.getDefaultDS()));
        // FactoryBean生成的bean没有自动调用afterPropertiesSet，需手动调用afterPropertiesSet
        dynamicDataSource.afterPropertiesSet();
        return dynamicDataSource;
    }

    @Override
    public Class<?> getObjectType() {
        return DataSource.class;
    }

    /**
     * 初始化所有数据源
     *
     * @return
     */
    private Map<Object, Object> initAllRealDataSource() {

        Map<Object, Object> realDataSourceMap = new HashMap<>();
        List<DynamicProperties.RealDataSource> dataSources = dynamicProperties.getDataSources();
        for (DynamicProperties.RealDataSource realDataSource : dataSources) {
            realDataSourceMap.put(realDataSource.getName(), buildDataSource(realDataSource));
        }
        return realDataSourceMap;
    }

    /**
     * 构建数据源
     */
    private DataSource buildDataSource(DynamicProperties.RealDataSource realDataSource) {
        String type = realDataSource.getType();
        if (StringUtils.isBlank(type)) {
            type = "com.alibaba.druid.pool.DruidDataSource";
        }
        try {
            Class<? extends DataSource> dataSourceType = (Class<? extends DataSource>) Class.forName(type);
            String driverClassName = realDataSource.getDriverClassName();
            String url = realDataSource.getUrl();
            String username = realDataSource.getUsername();
            String password = realDataSource.getPassword();
            DataSourceBuilder<?> factory = DataSourceBuilder.create()
                    .driverClassName(driverClassName)
                    .url(url)
                    .username(username)
                    .password(password)
                    .extraProp(realDataSource.getExtraProps())
                    .type(dataSourceType);
            return factory.build();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("未找到该类" + type);
        }

    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
